package com.example.librarymanagement.controller;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.librarymanagement.dto.borrowrecord.BorrowRecordAddDto;
import com.example.librarymanagement.dto.borrowrecord.BorrowRecordDto;
import com.example.librarymanagement.dto.borrowrecord.BorrowRecordListDto;
import com.example.librarymanagement.dto.borrowrecord.BorrowRecordUpdDto;
import com.example.librarymanagement.entity.*;
import com.example.librarymanagement.exception.BizException;
import com.example.librarymanagement.result.ResultCode;
import com.example.librarymanagement.util.CheckEntityUtil;
import com.example.librarymanagement.util.EnumConst;
import com.example.librarymanagement.vo.BorrowRecordVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.WebRequest;

import javax.validation.constraints.NotNull;
import java.security.Principal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author LQS
 */
@RestController
@Api("借阅记录模块")
@RequestMapping("/borrowRecord")
public class BorrowRecordController extends BaseController {

    @GetMapping
    @ApiOperation(value = "查询借阅信息")
    @PreAuthorize("hasAnyAuthority('borrowRecord:manage:list','periodical:list:view')")
    public IPage<BorrowRecordVo> getBookRecordList(@Validated BorrowRecordListDto borrowRecordListDto, Principal principal) {
        //1表示为用户查询自己的记录
        if (borrowRecordListDto.getUser() == 1) {
            User user = CheckEntityUtil.isNullByColumnEq("username", principal.getName(), userService, ResultCode.USER_ACCOUNT_NOT_EXIST);
            Reader reader = readerService.getOne(new QueryWrapper<Reader>().inSql("id", "select reader_id from t_user_reader where user_id = " + user.getId()));
            borrowRecordListDto.setReaderName(reader.getName());
        }
        if (borrowRecordListDto.getBookPeriodical().equals(EnumConst.BOOK.getCode())) {
            return borrowRecordService.getBookBorrow(borrowRecordListDto);
        } else {
            return borrowRecordService.getPeriodicalBorrow(borrowRecordListDto);
        }
    }

    @GetMapping("/info/{id}")
    @ApiOperation("通过id查询借阅信息")
    @PreAuthorize("hasAnyAuthority('borrowRecord:manage:list','periodical:list:view')")
    public BorrowRecordVo info(@PathVariable Integer id) {
        BorrowRecord borrowRecord = CheckEntityUtil.isNullById(id, borrowRecordService, ResultCode.BORROW_RECORD_NOT_FOUND);
        BorrowRecordVo borrowRecordVo = new BorrowRecordVo();
        borrowRecordVo.setId(borrowRecord.getId());
        borrowRecordVo.setReturnDate(borrowRecord.getReturnDate());
        borrowRecordVo.setShouldReturnDate(borrowRecord.getShouldReturnDate());
        borrowRecordVo.setState(borrowRecord.getState());
        return borrowRecordVo;
    }

    @GetMapping("/readerAndBook/{bookPeriodical}")
    @ApiOperation("获取读者和图书信息")
    @PreAuthorize("hasAnyAuthority('borrowRecord:manage:list','periodical:list:view')")
    public Map<String, List> getReaderAndBookList(@PathVariable Integer bookPeriodical) {
        List<UserReader> userReaderList = userReaderService.list();
        List<Map<String, Object>> readerOptions = new ArrayList<>();
        for (int i = 0; i < userReaderList.size(); i++) {
            UserReader userReader = userReaderList.get(i);
            User user = userService.getById(userReader.getUserId());
            Reader reader = readerService.getById(userReader.getReaderId());
            Map<String, Object> map = new HashMap<>(2);
            readerOptions.add(i, MapUtil.builder(map).put("id", reader.getId())
                    .put("reader", user.getPhone() + "（" + reader.getName() + "）").map());
        }
        Map<String, List> map = new HashMap<>(2);
        return MapUtil.builder(map).put("bookOptions", bookPeriodical.equals(EnumConst.BOOK.getCode()) ? bookService.list() : periodicalTypeService.list())
                .put("readerOptions", readerOptions).map();
    }

    @PostMapping
    @ApiOperation(value = "增加借阅信息")
    @PreAuthorize("hasAuthority('borrowRecord:manage:save')")
    public void addBookRecord(@Validated @RequestBody BorrowRecordAddDto borrowRecordAddDto) {

        Reader reader = CheckEntityUtil.isNullById(borrowRecordAddDto.getReaderId(), readerService, ResultCode.USER_ACCOUNT_NOT_EXIST);
        Date date = new Date();
        BorrowRecord borrowRecord = new BorrowRecord();

        if (borrowRecordAddDto.getBookPeriodical().equals(EnumConst.BOOK.getCode())) {
            Book book = CheckEntityUtil.isNullById(borrowRecordAddDto.getBookId(), bookService, ResultCode.BOOK_ACCOUNT_NOT_EXIST);
            book.setCount(book.getCount() - 1);
            if (book.getCount() <= book.getTotal() && book.getCount() >= 0) {
                borrowRecord.setBorrowDate(new Date());
                borrowRecord.setShouldReturnDate(new Date(date.getTime() + 30L * 24L * 60L * 60L * 1000L));
                borrowRecordAddDto.convertToEntity(borrowRecord);
                borrowRecordService.save(borrowRecord);
                bookService.updateById(book);

                reader.setBorrowCount(reader.getBorrowCount() + 1);
                readerService.updateById(reader);
            } else {
                throw new BizException(ResultCode.BOOK_NUMBER_RUN_SHORT);
            }
        } else {
            Periodical periodical = CheckEntityUtil.isNullById(borrowRecordAddDto.getBookId(), periodicalService, ResultCode.PERIODICAL_ACCOUNT_NOT_EXIST);
            periodical.setCount(periodical.getCount() - 1);
            if (periodical.getCount() <= periodical.getTotal() && periodical.getCount() > 0) {
                borrowRecord.setBorrowDate(new Date());
                borrowRecord.setShouldReturnDate(new Date(date.getTime() + 30L * 24L * 60L * 60L * 1000L));
                borrowRecordAddDto.convertToEntity(borrowRecord);
                borrowRecordService.save(borrowRecord);
                periodicalService.updateById(periodical);

                reader.setBorrowCount(reader.getBorrowCount() + 1);
                readerService.updateById(reader);
            } else {
                throw new BizException(ResultCode.PERIODICAL_NUMBER_RUN_SHORT);
            }
        }
    }

    @DeleteMapping
    @ApiOperation(value = "删除借阅信息")
    @PreAuthorize("hasAuthority('borrowRecord:manage:delete')")
    @Transactional(rollbackFor = {Exception.class})
    public void delBookRecord(@NotNull(message = "id值不能为空") Integer id) {
        BorrowRecord borrowRecord = CheckEntityUtil.isNullById(id, borrowRecordService, ResultCode.BORROW_RECORD_NOT_FOUND);
        if (borrowRecord.getState().equals(EnumConst.BORROW_RECORD_STATE_NOT_RETURN.getCode())) {
            Reader reader = readerService.getById(borrowRecord.getReaderId());
            reader.setBorrowCount(reader.getBorrowCount() - 1);
            readerService.updateById(reader);
            if (borrowRecord.getBookPeriodical().equals(EnumConst.BOOK.getCode())) {
                Book book = bookService.getById(borrowRecord.getBookId());
                book.setCount(book.getCount() + 1);
                bookService.updateById(book);
            } else {
                Periodical periodical = periodicalService.getById(borrowRecord.getBookId());
                periodical.setCount(periodical.getCount() + 1);
                periodicalService.updateById(periodical);
            }
        }
        borrowRecordService.removeById(id);
    }


    @PutMapping
    @ApiOperation(value = "更新借阅信息")
    @Transactional(rollbackFor = {Exception.class})
    @PreAuthorize("hasAuthority('borrowRecord:manage:update')")
    public void updBookRecord(@Validated @RequestBody BorrowRecordUpdDto borrowRecordUpdDto) {
        BorrowRecord borrowRecord = CheckEntityUtil.isNullById(borrowRecordUpdDto.getId(), borrowRecordService, ResultCode.BORROW_RECORD_NOT_FOUND);
        borrowRecordUpdDto.convertToEntity(borrowRecord);
        if (borrowRecordUpdDto.getReturnDate() == null && borrowRecordUpdDto.getState().equals(EnumConst.BORROW_RECORD_STATE_RETURN.getCode())) {
            returnBook(borrowRecord.getId());

        } else {
            borrowRecord.setReturnDate(null);
        }
        borrowRecordService.updateById(borrowRecord);

    }


    @PutMapping("/{id}")
    @ApiOperation(value = "用户还书")
    @PreAuthorize("hasAnyRole('normal','admin')")
    @Transactional(rollbackFor = {Exception.class})
    public void returnBook(@PathVariable Integer id) {
        BorrowRecord borrowRecord = CheckEntityUtil.isNullById(id, borrowRecordService, ResultCode.BORROW_RECORD_NOT_FOUND);
        if (borrowRecord.getState().equals(EnumConst.BORROW_RECORD_STATE_NOT_RETURN.getCode()) && borrowRecord.getReturnDate() == null) {
            borrowRecord.setState(EnumConst.BORROW_RECORD_STATE_RETURN.getCode());
            borrowRecord.setReturnDate(new Date());
            borrowRecordService.updateById(borrowRecord);
            Reader reader = CheckEntityUtil.isNullById(borrowRecord.getReaderId(), readerService, ResultCode.USER_ACCOUNT_NOT_EXIST);
            reader.setReturnCount(reader.getReturnCount() + 1);
            readerService.updateById(reader);
        } else {
            throw new BizException(ResultCode.BORROW_RETURN);
        }
        if (borrowRecord.getBookPeriodical().equals(EnumConst.BOOK.getCode())) {
            Book book = CheckEntityUtil.isNullById(borrowRecord.getBookId(), bookService, ResultCode.BOOK_ACCOUNT_NOT_EXIST);
            book.setCount(book.getCount() + 1);
            bookService.updateById(book);
        } else {
            Periodical periodical = CheckEntityUtil.isNullById(borrowRecord.getBookId(), periodicalService, ResultCode.PERIODICAL_ACCOUNT_NOT_EXIST);
            periodical.setCount(periodical.getCount() + 1);
            periodicalService.updateById(periodical);
        }

    }

    @PostMapping("/userBorrow")
    @Transactional(rollbackFor = {Exception.class})
    @ApiOperation(value = "用户借阅图书")
    @PreAuthorize("hasAnyRole('normal','admin')")
    public void borrowBook(@Validated @RequestBody BorrowRecordDto borrowRecordDto, Principal principal) {
        User user = CheckEntityUtil.isNullByColumnEq("username", principal.getName(), userService, ResultCode.USER_ACCOUNT_NOT_EXIST);

        Date date = new Date();

        if (borrowRecordDto.getBookPeriodical().equals(EnumConst.BOOK.getCode())) {
            Book book = CheckEntityUtil.isNullById(borrowRecordDto.getBookId(), bookService, ResultCode.BOOK_ACCOUNT_EXIST);
            book.setCount(book.getCount() - 1);
            bookService.updateById(book);
        } else {
            Periodical periodical = CheckEntityUtil.isNullById(borrowRecordDto.getBookId(), periodicalService, ResultCode.PERIODICAL_ACCOUNT_NOT_EXIST);
            periodical.setCount(periodical.getCount() - 1);
            periodicalService.updateById(periodical);
        }

        Reader reader = readerService.getOne(new QueryWrapper<Reader>().inSql("id", "select reader_id from t_user_reader where user_id = " + user.getId()));
        reader.setBorrowCount(reader.getBorrowCount() + 1);
        readerService.updateById(reader);

        BorrowRecord borrowRecord = new BorrowRecord();
        borrowRecord.setBookId(borrowRecordDto.getBookId());
        borrowRecord.setReaderId(reader.getId());
        borrowRecord.setBookPeriodical(borrowRecordDto.getBookPeriodical());
        borrowRecord.setBorrowDate(date);
        borrowRecord.setShouldReturnDate(new Date(date.getTime() + 30L * 24L * 60L * 60L * 1000L));
        borrowRecord.setState(0);
        borrowRecordService.save(borrowRecord);
    }

    @InitBinder
    public void initBinder(WebDataBinder binder, WebRequest request) {
        //转换日期 注意这里的转化要和传进来的字符串的格式一直 如2015-9-9 就应该为yyyy-MM-dd
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        // CustomDateEditor为自定义日期编辑器
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }
}
